package com.crane.oss.sys.service.impl;
import java.util.Date;


import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crane.common.core.utils.PinyinUtil;
import com.crane.common.core.utils.StringUtil;
import com.crane.oss.common.model.DynamicCode;
import com.crane.oss.sys.bean.request.user.*;
import com.crane.oss.sys.bean.resp.*;
import com.sun.javafx.binding.StringFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.crane.common.core.dto.SessUser;
import com.crane.common.core.exception.AppException;
import com.crane.common.core.exception.BasicErrorCode;
import com.crane.common.core.exception.BizException;
import com.crane.common.core.exception.SysException;
import com.crane.common.core.utils.CollectionUtil;
import com.crane.common.core.utils.Md5Util;
import com.crane.common.framework.utils.BeanUtil;
import com.crane.oss.common.bean.request.QueryDynamicCodeRequest;
import com.crane.oss.sys.bean.request.role.QueryPartyRoleRequest;
import com.crane.oss.sys.dao.UserDao;
import com.crane.oss.sys.dao.UserPartyDao;
import com.crane.oss.enums.DynamicCodeTypeEnum;
import com.crane.oss.enums.UserStatusEnum;
import com.crane.oss.enums.UserTypeEnum;
import com.crane.oss.sys.model.User;
import com.crane.oss.sys.model.UserParty;
import com.crane.oss.common.service.DynamicCodeService;
import com.crane.oss.sys.service.ApiService;
import com.crane.oss.sys.service.PartyRoleService;
import com.crane.oss.sys.service.PartyService;
import com.crane.oss.sys.service.RoleService;
import com.crane.oss.sys.service.UserPartyService;
import com.crane.oss.sys.service.UserRoleService;
import com.crane.oss.sys.service.UserService;

@Service("userService")
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Resource
    private UserDao userDao;
    @Resource
    private UserPartyDao userPartyDao;

    @Resource
    private RoleService roleService;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private UserPartyService userPartyService;
    @Resource
    private PartyService partyService;
    @Resource
    private PartyRoleService partyRoleService;
    @Resource
    private ApiService apiService;

    @Resource
    private DynamicCodeService dynamiccodeService;


    @Override
    public UserBean userLogin(String username, String password, String hostName) {
        logger.info("UserServiceImpl userLogin username={},hostName={}", username, hostName);
        Map<String, Object> map = new HashMap<>();
        map.put("username", username);
        User _user = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,username));
        if (null == _user) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        // 账号锁定
        if (_user.getStatus().equals(UserStatusEnum.DISABLE.getValue())) {
            throw new BizException("账号已锁定");
        } else if (_user.getStatus().equals(UserStatusEnum.LOCK.getValue())) {
            throw new BizException("账号已锁定");
        }
        if (null != _user.getLoginFailCount() && _user.getLoginFailCount() >= 5) {
            throw new BizException("账号超过最大次数");
        }

        String sKey = password + _user.getMobile();
        try {
            password = Md5Util.md5EncodeBase64(sKey);
        } catch (Exception e) {
            throw new BizException();
        }

        User updateUser = new User();
        updateUser.setUserId(_user.getUserId());
        updateUser.setLastLoginTime(new Date());
        // 密码错误
        if (!password.equals(_user.getPassword())) {
            if (null == _user.getLoginFailCount()) {
                updateUser.setLoginFailCount(1);
            } else {
                // 不管并发试密码问题
                updateUser.setLoginFailCount(_user.getLoginFailCount() + 1);
            }
            if (null != _user.getLoginFailCount() && _user.getLoginFailCount() >= 4) {
                updateUser.setStatus(UserStatusEnum.LOCK.getValue());
            }
            userDao.updateById(updateUser);
            throw new BizException("密码错误");
        }
        updateUser.setLoginFailCount(0);
        updateUser.setLastLoginIp(hostName);
        userDao.updateById(updateUser);

        UserBean userBean = new UserBean();
        userBean.setLastLoginIp(hostName);
        BeanUtil.copyProperties(_user, userBean);
        return userBean;
    }

    @Override
    public Set<String> queryAllPerms(SessUser opUser) {
        logger.info("UserServiceImpl queryAllPerms opUser={}", opUser);
        Long userId = null;
        if (!opUser.getUserType().equals(UserTypeEnum.SUPER_ADMIN.getType())) {
            userId = opUser.getUserId();
        }
        Set<String> permissions = new HashSet<>();
        List<ApiBean> apiList = apiService.queryApiListByUser(userId);
        for (ApiBean apiBean : apiList) {
            if (StringUtils.hasText(apiBean.getPermission())) {
                permissions.add(apiBean.getPermission());
            }
        }
        return permissions;
    }

    @Override
    public UserBean queryUser(Long opPartyId, Long userId) {
        logger.info("UserServiceImpl queryViewBean userId={}", userId);
        User user = userDao.selectById(userId);
        if (null == user) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        UserBean userBean = new UserBean();
        BeanUtil.copyProperties(user, userBean);
        // 查询用户机构
        PartyBean partyBean = validateUserRight(opPartyId, userBean.getUserId(), false);
        userBean.setPartyId(partyBean.getPartyId());
        userBean.setPartyCode(partyBean.getPartyCode());
        userBean.setPartyName(partyBean.getNameCn());

        // 查询所属角色
        List<Long> roleIdList = new ArrayList<>();
        userBean.setRoleIdList(roleIdList);
        List<RoleBean> roleList = roleService.getUserRole(userBean);
        if (null != roleList && roleList.size() != 0) {
            userBean.setRoleBeanList(roleList);
            for (RoleBean roleBean : roleList) {
                roleIdList.add(roleBean.getId());
            }
        }
        return userBean;
    }

    @Override
    public IPage<UserBean> queryList(QueryUserRequest queryRequest) {
        logger.info("UserServiceImpl queryList queryRequest={}", JSON.toJSON(queryRequest));
        IPage<User> page = userDao.selectPageUserList(new Page<>(queryRequest.getPageNo(), queryRequest.getPageSize()), queryRequest);
        if(CollectionUtil.isNotEmpty(page.getRecords())){
            List<Long> userIds=page.getRecords().stream().map(User :: getUserId).collect(Collectors.toList());
            List<UserRoleBean>  userRoleBeanList=userRoleService.queryRoleIdList(userIds);
            Map<Long,List<UserRoleBean>> map=userRoleBeanList.stream().collect(Collectors.groupingBy(UserRoleBean :: getUserId));
            return page.convert(u -> {
                UserBean v = new UserBean();
                BeanUtils.copyProperties(u, v);
                if(CollectionUtil.isNotEmpty(map.get(u.getUserId()))){
                    v.setRoleBeanList(BeanUtil.copyList(map.get(u.getUserId()),RoleBean.class));
                }
                return v;
            });
        }else{
            return new Page<>(queryRequest.getPageNo(), queryRequest.getPageSize());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long save(AddUserRequest request) {
        logger.info("UserServiceImpl save request={}", request);
        //新增用户机构代码
        String partyCode = request.getPartyCode();
        Long partyId = null;
        PartyBean partyBean= null;
        boolean addFlag =true;
        Integer userType;
        if (StringUtils.isEmpty(partyCode)) {
            partyId=request.getCreatePartyId();
            partyBean=partyService.queryParty(request.getCreatePartyId());
            userType=UserTypeEnum.COMMON_USER.getType();
        }else{
            partyBean = partyService.queryPartyByCode(partyCode);
            partyId = partyBean.getPartyId();
            userType=UserTypeEnum.SYSTEM_ADMIN.getType();
            //添加指定子机构
            if (partyBean.getLineage().indexOf(request.getCreatePartyId().toString()) == -1) {
                throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
            }
        }
        // 检查用户是否已存在
        User checkUser = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,request.getUserName()));
        if (checkUser != null) {

            //检测是否为同一个机构
            List<UserParty> list=userPartyDao.selectList(Wrappers.lambdaQuery(UserParty.class)
                    .eq(UserParty::getUserId,checkUser.getUserId()));
            for(UserParty userParty : list){
                if(userParty.getPartyId().equals(partyId)){
                    throw new AppException(BasicErrorCode.ENTITY_IS_EXISTS, "后台管理用户");
                }
            }
        }
        if(null != request.getMobile()) {
            User check = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getMobile, request.getMobile()));
            if (check != null) {
                throw new AppException(BasicErrorCode.ENTITY_IS_EXISTS, "手机号码");
            }
        }
        //当前保存的角色列表
        List<Long> roleIdList = request.getRoleIdList();
        if(null == roleIdList){
            roleIdList=new ArrayList<>();
        }
        if (CollectionUtil.isNotEmpty(roleIdList)) {
            // 验证角色是当前人创建的角色
            roleService.validatorRole(roleIdList, request.getCreateUserId());
        }
        // 查找机构类型对应的角色
        QueryPartyRoleRequest queryPartyRoleRequest = new QueryPartyRoleRequest();
        queryPartyRoleRequest.setPartyType(partyBean.getPartyType());
        queryPartyRoleRequest.setUserType(userType);
        List<PartyRoleBean> roleList = partyRoleService.queryList(queryPartyRoleRequest).getRecords();
        if (CollectionUtils.isEmpty(roleList)) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "机构对应的角色");
        }
        for (PartyRoleBean partyRoleBean : roleList) {
            roleIdList.add(partyRoleBean.getRoleId());
        }
        if (CollectionUtil.isEmpty(roleIdList)) {
            throw new AppException(BasicErrorCode.PARAS_IS_NOT_NULL, "角色");
        }
        return createUser(request,roleIdList, partyId, userType,checkUser == null ? null : checkUser.getUserId());
    }

    @Override
    public boolean addUser(String userName, Long opPartyId) {
        // 检查用户是否已存在
        User checkUser = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUserName,userName));
        if (checkUser == null) {
            return  false;
        }
        //检测是否为同一个机构
        Long partyId = null;
        List<UserParty> list=userPartyDao.selectList(Wrappers.lambdaQuery(UserParty.class)
                .eq(UserParty::getUserId,checkUser.getUserId()));
        for(UserParty userParty : list){
            if(!userParty.getPartyId().equals(opPartyId)){
                partyId =userParty.getPartyId();
                break;
            }
        }
        if(null == partyId){
            return false;
        }
        UserParty userParty=new UserParty();
        userParty.setUserId(checkUser.getUserId());
        userParty.setPartyId(opPartyId);
        userParty.setCreateUserId(checkUser.getUserId());
        userParty.setCreateTime(new Date());
        userPartyDao.insert(userParty);
        return true;
    }

    private Long createUser(AddUserRequest request,List<Long> roleIdList, Long partyId, Integer userType,Long userId) {
        User newUser = new User();
        newUser.setUserId(userId);
        newUser.setCreateUserId(request.getCreateUserId());
        newUser.setUserType(userType);
        _bulidSysUserEntity(request, newUser);
        if(null == userId){
            userDao.insert(newUser);
        }
        // 用户角色关系
        userRoleService.saveOrUpdate(newUser.getUserId(), roleIdList, request.getCreateUserId());
        // 用户机构表
        UserParty userParty = new UserParty();
        userParty.setUserId(newUser.getUserId());
        userParty.setPartyId(partyId);
        userParty.setCreateUserId(request.getCreateUserId());
        userParty.setCreateTime(new Date());
        userPartyDao.insert(userParty);
        return newUser.getUserId();
    }

    @Override
    public void updatePassword(String username, UpdateUserPassWordRequest request) {
        logger.info("UserServiceImpl updatePassword username={}，request={}", username, request);
        User user = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,username));
        if (user == null) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        String oldPassword = request.getPassword() + user.getMobile();
        try {
            // 加密旧密码
            oldPassword = Md5Util.md5EncodeBase64(oldPassword);
        } catch (Exception e) {
            logger.error("{}:密码加密错误,error::{}", username, e);
            throw new SysException();
        }
        if (!oldPassword.equals(user.getPassword())) {
            throw new BizException("密码错误");
        }
        String newPassword = request.getNewPassword() + username;
        newPassword = Md5Util.md5EncodeBase64(newPassword);
        if (newPassword.equals(user.getPassword())) {
            throw new BizException("新密码与原来密码一致");
        }
        user.setPassword(newPassword);
        user.setUpdateTime(new Date());
        userDao.updateById(user);
    }

    @Override
    public void updateState(UpdateUserStateRequest request) {
        User user = userDao.selectById(request.getUserId());
        if (null == user) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        validateUserRight(request.getUpdatePartyId(), user.getUserId(), false);
        user.setStatus(request.getStatus());
        user.setUpdateTime(new Date());
        user.setUpdateUserId(request.getUpdateUserId());
        userDao.updateById(user);

    }

    @Override
    public void forgetPassword(ForgetUserPassWordRequest request) {
        logger.info("UserServiceImpl forgetPassword request={}", request);
        // 检查用户是否已存在
        User checkUser =userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getMobile,request.getPhone()));
        if (checkUser == null) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        if (checkUser.getStatus().equals(UserStatusEnum.DISABLE.getValue())) {
            throw new BizException("账号已禁用");
        }
        // 验证接受手机号码
        if (!checkUser.getMobile().equals(request.getPhone())) {
            throw new BizException("手机验证码不一致");
        }
        // 验证短信验证码
        QueryDynamicCodeRequest queryDynamicCodeRequest = new QueryDynamicCodeRequest();
        queryDynamicCodeRequest.setUserId(checkUser.getUserName());
        queryDynamicCodeRequest.setBizType(DynamicCodeTypeEnum.FORGET_PASSWORD.getValue());
        queryDynamicCodeRequest.setDynaCode(request.getVerifyCode());
        queryDynamicCodeRequest.setRefNo(request.getPhone());
        dynamiccodeService.validateCode(queryDynamicCodeRequest);
        // 修改密码
        String newPassword = request.getNewPassword()
                + checkUser.getMobile();
        newPassword = Md5Util.md5EncodeBase64(newPassword);
        User _user = new User();
        _user.setUserId(checkUser.getUserId());
        _user.setPassword(newPassword);
        _user.setStatus(UserStatusEnum.VALID.getValue());
        _user.setLoginFailCount(0);
        _user.setUpdateTime(new Date());
        userDao.updateById(_user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UpdateUserRequest updateRequest) {
        logger.info("UserServiceImpl update request={}", JSON.toJSON(updateRequest));

        User user = userDao.selectById(updateRequest.getUserId());
        if (null == user) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        if(null != updateRequest.getUserName() && !updateRequest.getUserName().equals(user.getUserName())){
            User checkUser =userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,updateRequest.getUserName()));
            if (checkUser != null) {
                throw new AppException(BasicErrorCode.ENTITY_IS_EXISTS, "用户名");
            }
            user.setUserName(updateRequest.getUserName());
        }
        if(null != updateRequest.getMobile() && !updateRequest.getMobile().equals(user.getMobile())){
            User checkUser =userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getMobile,updateRequest.getMobile()));
            if (checkUser != null) {
                throw new AppException(BasicErrorCode.ENTITY_IS_EXISTS, "手机号码");
            }
            user.setMobile(updateRequest.getMobile());
            //修改手机号码重置密码
            String password = "zhty"+updateRequest.getMobile().substring(user.getMobile().length() - 4) + updateRequest.getMobile();
            try {// 加密
                password = Md5Util.md5EncodeBase64(password);
                user.setPassword(password);
            } catch (Exception e) {
                logger.error("{}:密码加密错误,error::{}", user.getUserName(), e);
                String errMsg = "密码加密错误";
                throw new BizException(errMsg);
            }
        }
        // 验证同一机构权限
        PartyBean partyBean = validateUserRight(updateRequest.getUpdatePartyId(), user.getUserId(), false);
        if (updateRequest.getUpdatePartyId().equals(partyBean.getPartyId())) {
            if (!CollectionUtils.isEmpty(updateRequest.getRoleIdList())) {
                List<Long> updateRoleList = new ArrayList<>();
                updateRoleList.addAll(updateRequest.getRoleIdList());
                // 查询用户已经存在的角色,不需要校验，可能是其他管理员创建.
                UserBean userBean = new UserBean();
                userBean.setUserId(user.getUserId());
                userBean.setUserType(user.getUserType());
                List<RoleBean> roleLs = roleService.getUserRole(userBean);
                for (RoleBean roleBean : roleLs) {
                    updateRoleList.remove(roleBean.getId());
                }
                roleService.validatorRole(updateRoleList, updateRequest.getUpdateUserId());
            }
        }
        user.setRealName(updateRequest.getRealName());
        user.setEmail(updateRequest.getEmail());
        user.setStatus(updateRequest.getStatus());
        user.setUserLabel(updateRequest.getUserLabel());
        user.setHeadUrl(updateRequest.getHeadUrl());
        user.setSex(updateRequest.getSex());
        user.setUpdateTime(new Date());
        user.setUpdateUserId(updateRequest.getUpdateUserId());
        userDao.updateById(user);

        if (!CollectionUtils.isEmpty(updateRequest.getRoleIdList())) {
            // 用户角色关系
            userRoleService.saveOrUpdate(updateRequest.getUserId(), updateRequest.getRoleIdList(), updateRequest.getUpdateUserId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long userId, Long opPartId) {
        logger.info("UserServiceImpl delete userId={}", userId);
        // 查询用户信息
        User user = userDao.selectById(userId);
        if (null == user) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        // 管理员角色不能删除
        if (!user.getUserType().equals(UserTypeEnum.COMMON_USER.getType())) {
            throw new BizException("系统管理角色不能删除");
        }
        validateUserRight(opPartId, user.getUserId(), false);
        userDao.deleteById(userId);
        userRoleService.deleteByUserId(userId);
        userPartyService.deleteByUserId(userId);
    }

    @Override
    public PartyBean validateUserRight(Long checkPartyId, Long userId, Boolean flag) {
        logger.info("UserServiceImpl validateUserRight userId={}，flag={}", userId, flag);
        List<PartyBean>  partyBeanList = partyService.queryPartyByUserId(userId);
        for(PartyBean partyBean : partyBeanList){
            if (checkPartyId.equals(partyBean.getPartyId())) {
                return partyBean;
            }
            if (!flag) {
                String[] partIds = partyBean.getLineage().split("|");
                for (String temp : partIds) {
                    if (temp.equals(checkPartyId.toString())) {
                        return partyBean;
                    }
                }
            }
        }
        throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
    }

    @Override
    public UserBean queryUserByName(String userName) {
        logger.info("UserServiceImpl queryUserByName userName={}", userName);
        User checkUser = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,userName));
        if (checkUser == null) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
        if (checkUser.getStatus().equals(UserStatusEnum.DISABLE.getValue())) {
            throw new BizException("账户已禁用");
        }
        UserBean userBean = new UserBean();
        BeanUtil.copyProperties(checkUser, userBean);
        return userBean;
    }

    @Override
    public UserBean queryUserById(Long userId) {
        User checkUser = userDao.selectById(userId);
        if (checkUser == null) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户");
        }
//        if (checkUser.getStatus().equals(UserStatusEnum.DISABLE.getValue())) {
//            throw new BizException("账户已禁用");
//        }
        UserBean userBean = new UserBean();
        BeanUtil.copyProperties(checkUser, userBean);
        return userBean;
    }

    @Override
    public UserBean queryUserByMobile(String mobile,String password) {
        User user = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getMobile,mobile));
        if(StringUtil.isNotEmpty(password)){
            if(!user.getPassword().equals(Md5Util.md5EncodeBase64(password))){
                return  null;
            }
        }
        if(null != user){
            UserBean userBean=new UserBean();
            BeanUtil.copyProperties(user,userBean);
            return userBean;
        }
        return null;
    }

    @Override
    public String getUserName(String realName) {
        String userName= PinyinUtil.getPinYin(realName);
        User user = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,userName));
        if(null != user){
            userName=userName+String.format("%04d", new Random().nextInt(9999));
            user = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,userName));
            if(null != user){
                throw new AppException("请重新再试");
            }
        }
        return userName;
    }

    private void _bulidSysUserEntity(AddUserRequest user, User newUser) {
        newUser.setUserName(user.getUserName());
        newUser.setRealName(user.getRealName());
        newUser.setEmail(user.getEmail());
        newUser.setMobile(user.getMobile());
        newUser.setUserLabel(user.getUserLabel());
        newUser.setHeadUrl(user.getHeadUrl());
        newUser.setSex(user.getSex());
        newUser.setStatus(user.getStatus() == null ? UserStatusEnum.VALID.getValue() : user.getStatus());
        newUser.setCreateTime(new Date());
        String userName = user.getUserName();
        if (StringUtils.isEmpty(user.getPassword())) {
            String passwd ="zhty"+user.getMobile().substring(user.getMobile().length() - 4);
            user.setPassword(passwd);
        }
        String password = user.getPassword() + user.getMobile();
        try {// 加密
            password = Md5Util.md5EncodeBase64(password);
            newUser.setPassword(password);
        } catch (Exception e) {
            logger.error("{}:密码加密错误,error::{}", userName, e);
            String errMsg = "密码加密错误";
            throw new BizException(errMsg);
        }
    }



    public static void main(String[] args) {
        System.out.println(Md5Util.md5EncodeBase64("12345615974161167"));
    }
}
